package org.firefly.db.meta;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.firefly.db.util.ArrayUtils;

public class DBMetaImpl implements IDBMeta{

//	protected Connection c;
	protected String schema = null;
	protected DatabaseMetaData dmd;
	protected DBMetaImpl(){}
	public DBMetaImpl(Connection c,String schema) throws SQLException{
//		this.c=c;
		this.dmd=c.getMetaData();
		this.schema= schema;
	}
	
	@Override
	public List<TableMeta> getTableMetas(boolean needColumnMetas,boolean needPKMetas,boolean needFKMetas,String[] tables) throws SQLException{
		List<TableMeta> ls = new ArrayList<TableMeta>();
		ResultSet rs = dmd.getTables(null, schema, null, new String[]{"TABLE"});
		try{
			while(rs.next()){
				String tableName = rs.getString("TABLE_NAME");
				if(tables == null || ArrayUtils.indexOf(tables, tableName,true) != -1){
					TableMeta tm = new TableMeta();
					tm.setName(tableName);
					if(needColumnMetas){
						List<ColumnMeta> colMetas = getColumnMetas(tableName);
						tm.setColumnMetaLs(colMetas);
					}
					if(needPKMetas){
						PK pkMeta = getPKMetas(tableName);
						if(pkMeta!=null)tm.getConstraintLs().add(pkMeta);
					}
					if(needFKMetas){
						List<FK> fkMetas = getFKMetas(tableName);
						tm.getConstraintLs().addAll(fkMetas);
					}
					ls.add(tm);
				}
			}
		}finally{
			rs.close();
		}
		return ls;
	}
	
	
	@Override 
	public List<ColumnMeta> getColumnMetas(String tableName) throws SQLException{
		List<ColumnMeta> ls = new ArrayList<ColumnMeta>(); 
		ResultSet rs = dmd.getColumns(null, schema, tableName, null);
		try{
			while(rs.next()){
				String columnName = rs.getString("COLUMN_NAME");
				int javaType = rs.getInt("DATA_TYPE");
				int length = rs.getInt("COLUMN_SIZE");
				Integer digits = rs.getInt("DECIMAL_DIGITS");
				String nullable = rs.getString("IS_NULLABLE");
				ColumnMeta cm = new ColumnMeta();
				cm.setColumnName(columnName);
				cm.setTableName(tableName);
				cm.setJavaType(javaType);
				cm.setLength(length);
				cm.setDecimal(digits);
				cm.setNullAble("YES".equals(nullable));
				ls.add(cm);
			}
		}finally{
			rs.close();
		}
		return ls;
	}
	
	/**
	 * 获取表主键
	 * @param tableName
	 * @return
	 * @throws SQLException
	 */
	@Override
	public PK getPKMetas(String tableName) throws SQLException{
		ResultSet rs = dmd.getPrimaryKeys(null, schema, tableName);
		PK p = null;
		try{
			while(rs.next()){
				if(p==null){
					p = new PK();
					String pkName = rs.getString("PK_NAME");
					String columnName = rs.getString("COLUMN_NAME");
					p.setName(pkName);
					p.setPkTableName(tableName);
					p.setPkTableColumn(columnName);
				}else{
					String columnName = rs.getString("COLUMN_NAME");
					p.setPkTableColumn(p.getPkTableColumn()+","+columnName);
				}
			}
		}finally{
			rs.close();
		}
		return p;
	}

	/**
	 * 获取表外键
	 * @param tableName
	 * @return
	 * @throws SQLException
	 */
	@Override
	public List<FK> getFKMetas(String tableName) throws SQLException{
		List<FK> ls = new ArrayList<FK>(); 
		ResultSet rs = dmd.getExportedKeys(null, schema, tableName);
		try{
			while(rs.next()){
//				String pkTableName = rs.getString("PKTABLE_NAME");
				String pkColumnName = rs.getString("PKCOLUMN_NAME");
				String fkTableName = rs.getString("FKTABLE_NAME");
				String fkColumnName = rs.getString("FKCOLUMN_NAME");
				short onDeleteRule = rs.getShort("DELETE_RULE");
				String deleteRule=null;
				switch(onDeleteRule){
					case DatabaseMetaData.importedKeyCascade: deleteRule=" ON DELETE CASCADE ";break;//级联删除子表
					case DatabaseMetaData.importedKeySetNull: deleteRule=" ON DELETE SET NULL ";break;//设置外键为NULL
				}
				String fkName = rs.getString("FK_NAME");
				String pkName = rs.getString("PK_NAME");
				FK f = new FK();
				f.setPkTableName(tableName);
				f.setPkTableColumn(pkColumnName);
				f.setFkTableName(fkTableName);
				f.setFkTableColumn(fkColumnName);
				f.setName(fkName);
				f.setPkName(pkName);
				f.setDeleteRule(deleteRule);
				ls.add(f);
			}
		}finally{
			rs.close();
		}
		return ls;
	}

}
